package com.muicc.pdf;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.multipdf.PDFMergerUtility;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.text.PDFTextStripperByArea;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;

public class pdfparser {
    /**
     * 从base64编码的字符串加载pdf文件
     *
     * @param base64
     *               base64编码的字符串
     *
     * 
     * @return PDDocument
     */
    public static PDDocument Base64toPDF(String base64) {
        byte[] src = Base64.getDecoder().decode(base64);
        try {
            PDDocument document = Loader.loadPDF(src);
            return document;
        } catch (IOException e) {
            return null;
        }
    }

    /**
     * 把PDF文件分割成多个文件并解析银行回单
     *
     * @param stream
     *               输入流
     * @param height
     *               分割后pdf的高度
     * @param bank
     *               回单所属银行
     * @see com.muicc.pdf.Bank#ABC
     *
     * @return JSONArray,其每个成员都是一个回单对象
     */
    public static JSONArray splitPDF(InputStream stream, float height, Bank bank) {
        JSONArray val = new JSONArray();
        try {
            byte[] btys = stream.readAllBytes();
            PDDocument document = Loader.loadPDF(btys);
            PDFRenderer renderer = new PDFRenderer(document);
            for (int p = 0; p < document.getNumberOfPages(); p++) {
                PDPage page = document.getPage(p);
                float pheight = page.getMediaBox().getHeight();
                float pwidth = page.getMediaBox().getWidth();
                BufferedImage image = renderer.renderImageWithDPI(p, 300);
                for (int q = 0; (q + 1) * height < pheight + 1; q++) {
                    Rectangle2D rect = new Rectangle2D.Double(0, q * height, pwidth, height);
                    PDFTextStripperByArea pdfStripper = new PDFTextStripperByArea();
                    pdfStripper.addRegion("region", rect);
                    pdfStripper.extractRegions(page);
                    String txt = pdfStripper.getTextForRegion("region");
                    JSONObject obj = parseReceipt(txt, bank);
                    if (obj != null) {
                        val.add(obj);
                        PDDocument outputDocument = new PDDocument();
                        PDPage newpage = new PDPage(new PDRectangle(pwidth, height));
                        outputDocument.addPage(newpage);
                        BufferedImage chunkImage = image.getSubimage(0,
                                (int) (q * height / pheight * image.getHeight()), image.getWidth(),
                                (int) (height / pheight * image.getHeight()));
                        PDImageXObject img = LosslessFactory.createFromImage(outputDocument, chunkImage);
                        PDPageContentStream strm = new PDPageContentStream(outputDocument, newpage,
                                PDPageContentStream.AppendMode.OVERWRITE, true, true);
                        strm.drawImage(img, 0.0f, 0.0f, pwidth, height);
                        strm.close();
                        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                        outputDocument.save(outputStream);
                        outputDocument.close();
                        byte[] pdfBytes = outputStream.toByteArray();
                        obj.put("pdf", Base64.getEncoder().encodeToString(pdfBytes));
                        outputStream.close();
                    }
                }
            }
            document.close();
        } catch (Exception e) {
        }
        return val;
    }

    /**
     * 把PDF文件分割成多个文件并解析银行回单
     *
     * @param sPath
     *               PDF文件路径
     * @param height
     *               分割后pdf的高度
     * @param bank
     *               回单所属银行
     * @see com.muicc.pdf.Bank#ABC
     *
     * @return JSONArray,其每个成员都是一个回单对象
     */
    public static JSONArray splitPDF(String sPath, float height, Bank bank) {
        JSONArray val = new JSONArray();
        try {
            PDDocument document = Loader.loadPDF(new File(sPath));
            PDFRenderer renderer = new PDFRenderer(document);
            for (int p = 0; p < document.getNumberOfPages(); p++) {
                PDPage page = document.getPage(p);
                float pheight = page.getMediaBox().getHeight();
                float pwidth = page.getMediaBox().getWidth();
                BufferedImage image = renderer.renderImageWithDPI(p, 300);
                for (int q = 0; (q + 1) * height < pheight + 1; q++) {
                    Rectangle2D rect = new Rectangle2D.Double(0, q * height, pwidth, height);
                    PDFTextStripperByArea pdfStripper = new PDFTextStripperByArea();
                    pdfStripper.addRegion("region", rect);
                    pdfStripper.extractRegions(page);
                    String txt = pdfStripper.getTextForRegion("region");
                    JSONObject obj = parseReceipt(txt, bank);
                    if (obj != null) {
                        val.add(obj);
                        PDDocument outputDocument = new PDDocument();
                        PDPage newpage = new PDPage(new PDRectangle(pwidth, height));
                        outputDocument.addPage(newpage);
                        BufferedImage chunkImage = image.getSubimage(0,
                                (int) (q * height / pheight * image.getHeight()), image.getWidth(),
                                (int) (height / pheight * image.getHeight()));
                        PDImageXObject img = LosslessFactory.createFromImage(outputDocument, chunkImage);
                        PDPageContentStream strm = new PDPageContentStream(outputDocument, newpage,
                                PDPageContentStream.AppendMode.OVERWRITE, true, true);
                        strm.drawImage(img, 0.0f, 0.0f, pwidth, height);
                        strm.close();
                        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                        outputDocument.save(outputStream);
                        outputDocument.close();
                        byte[] pdfBytes = outputStream.toByteArray();
                        obj.put("pdf", Base64.getEncoder().encodeToString(pdfBytes));
                        outputStream.close();
                    }
                }
            }
            document.close();
        } catch (Exception e) {
        }
        return val;
    }

    /**
     * 从PDF文件读取文本
     *
     * @param sPath
     *              PDF文件路径
     *
     * @return 文件的所有内容
     */
    public static String readPDF(String sPath) {
        try {
            PDDocument document = Loader.loadPDF(new File(sPath));
            PDFTextStripper stripper = new PDFTextStripper();
            String text = stripper.getText(document);
            text = text.replaceAll("\\r\\n", "\n");
            document.close();
            return text;
        } catch (Exception e) {
        }
        return "";
    }

    /**
     * 从PDF文件流读取文本
     *
     * @param stream
     *               PDF文件流
     *
     * @return 文件的所有内容
     */
    public static String readPDF(InputStream stream) {
        try {
            byte[] btys = stream.readAllBytes();
            PDDocument document = Loader.loadPDF(btys);
            PDFTextStripper stripper = new PDFTextStripper();
            String text = stripper.getText(document);
            text = text.replaceAll("\\r\\n", "\n");
            document.close();
            return text;
        } catch (Exception e) {
        }
        return "";
    }

    /**
     * 从PDDocument读取文本
     *
     * @param doc
     *            PDDocument对象
     *
     * @return 文件的所有内容
     */
    public static String readPDF(PDDocument doc) {
        try {
            PDFTextStripper stripper = new PDFTextStripper();
            String text = stripper.getText(doc);
            text = text.replaceAll("\\r\\n", "\n");
            return text;
        } catch (Exception e) {
        }
        return "";
    }

    private static JSONObject parseReceipt(String txt, Bank bank) {
        switch (bank) {
            case ABC:
                return rABC(txt);
            case BOC:
                return rBOC(txt);
            case BOCF:
                return rBOCF(txt);
            case CCB:
                return rCCB(txt);
            case ICBC:
                return rICBC(txt);
            default:
                return new JSONObject();
        }
    }

    /**
     * 从PDF文件读取银行回单信息
     *
     * @param doc
     *             PDDocument对象
     *
     * @param bank
     *             回单所属银行
     * @see com.muicc.pdf.Bank#ABC
     *
     * @return JSONObject对象
     */
    public static JSONObject readReceipt(PDDocument doc, Bank bank) {
        String txt = readPDF(doc);
        return parseReceipt(txt, bank);
    }

    /**
     * 从PDF文件读取银行回单信息
     *
     * @param sPath
     *              PDF文件路径
     *
     * @param bank
     *              回单所属银行
     * @see com.muicc.pdf.Bank#ABC
     *
     * @return JSONObject对象
     */
    public static JSONObject readReceipt(String sPath, Bank bank) {
        String txt = readPDF(sPath);
        return parseReceipt(txt, bank);
    }

    /**
     * 从PDF文件流读取银行回单信息
     *
     * @param stream
     *               PDF文件流
     *
     * @param bank
     *               回单所属银行
     * @see com.muicc.pdf.Bank#ABC
     *
     * @return JSONObject对象
     */
    public static JSONObject readReceipt(InputStream stream, Bank bank) {
        String txt = readPDF(stream);
        return parseReceipt(txt, bank);
    }

    /**
     * @param origin
     * @return JSONObject
     */
    private static JSONObject rICBC(String origin) {
        JSONObject obj = new JSONObject();

        String regex = "日期: (20[0-9]{2}-[0|1][0-9]-[0-3][0-9])";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(origin);
        if (matcher.find()) {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            try {
                Date date = format.parse(matcher.group(1));
                obj.put("date", String.format("%tF", date));
            } catch (ParseException e) {
            }
        }
        regex = "回单编号: (\\d+)";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            obj.put("receiptCode", matcher.group(1));
        }
        regex = "付款人户名: (\\S*)\\s";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            obj.put("payer", matcher.group(1));
        }
        regex = "小写: ((\\d{1,3},)*\\d+\\.\\d{2})";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            obj.put("amount", Double.parseDouble(matcher.group(1).replace(",", "")));
        }
        regex = "用途: (\\S*)\\s?交易机构号";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            String v = formatString(matcher.group(1));
            obj.put("abstract", v);
        }
        regex = "摘要: (.*)\\n";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            String v = formatString(matcher.group(1));
            obj.put("comments", v);
        }
        obj.put("homeCharges", 0.00);
        obj.put("foreignCharges", 0.00);
        obj.put("currency", "CNY");
        return obj;
    }

    /**
     * @param origin
     * @return JSONObject
     */
    private static JSONObject rBOC(String origin) {
        if (origin.indexOf("国内支付业务收款回单", 0) < 0)
            return null;
        JSONObject obj = new JSONObject();
        String regex = "回单编号：(\\d+)";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(origin);
        if (matcher.find()) {
            obj.put("receiptCode", matcher.group(1));
        }
        regex = "日期：(20[0-9]{2}年[0|1][0-9]月[0-3][0-9]日)";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日");
            try {
                Date date = format.parse(matcher.group(1));
                obj.put("date", String.format("%tF", date));
            } catch (ParseException e) {
            }
        }
        regex = "\\s(\\S+(\\n\\S+\\n)*)收款人名称";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            obj.put("payer", matcher.group(1).replace("\n", ""));
        }
        regex = "金额：(\\D+)((\\d{1,3},)*\\d+\\.\\d{2})";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            obj.put("currency", Bank.parseCurrency(matcher.group(1)));
            obj.put("amount", Double.parseDouble(matcher.group(2).replace(",", "")));
        }
        regex = "用途：((.*)+)\\n";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            String v = formatString(matcher.group(1));
            obj.put("abstract", v);
        }
        regex = "\\n((.*))附言：";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            String v = formatString(matcher.group(1));
            obj.put("comments", v);
        }
        obj.put("homeCharges", 0.00);
        obj.put("foreignCharges", 0.00);
        return obj;
    }

    /**
     * @param origin
     * @return JSONObject
     */
    private static JSONObject rBOCF(String origin) {
        JSONObject obj = new JSONObject();
        String regex = "回单编号：(\\d+)";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(origin);
        if (matcher.find()) {
            obj.put("receiptCode", matcher.group(1));
        }
        regex = "Transaction Date：(20[0-9]{2}/[0|1][0-9]/[0-3][0-9])";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd");
            try {
                Date date = format.parse(matcher.group(1));
                obj.put("date", String.format("%tF", date));
            } catch (ParseException e) {
            }
        }
        regex = "Remitter's Name：(.+)\\n";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            obj.put("payer", matcher.group(1));
        }
        regex = "CCY/AMT：(\\D+)/((\\d{1,3},)*\\d+\\.\\d{2})";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            obj.put("currency", Bank.parseCurrency(matcher.group(1)));
            obj.put("amount", Double.parseDouble(matcher.group(2).replace(",", "")));
        }
        regex = "Bank's Remarks：((.*)+)\\n附言";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            String v = formatString(matcher.group(1));
            obj.put("abstract", v);
        }
        regex = "附言Remarks：((.*)+)\\n汇款产品";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            String v = formatString(matcher.group(1));
            obj.put("comments", v);
        }
        regex = "Receiver's Charges：\\D+((\\d{1,3},)*\\d+\\.\\d{2})\\s代兑机构名称";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            obj.put("homeCharges", Double.parseDouble(matcher.group(1).replace(",", "")));
        }
        regex = "Sender's Charges：\\D+((\\d{1,3},)*\\d+\\.\\d{2})\\s代兑机构账号";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            obj.put("foreignCharges", Double.parseDouble(matcher.group(1).replace(",", "")));
        }
        return obj;
    }

    /**
     * @param origin
     * @return JSONObject
     */
    private static JSONObject rCCB(String origin) {
        JSONObject obj = new JSONObject();
        String regex = "我行编号：([A-Z0-9]+)";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(origin);
        if (matcher.find()) {
            obj.put("receiptCode", matcher.group(1));
        }
        regex = "TRANSACTION DATE：(20[0-9]{2}[0|1][0-9][0-3][0-9])";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
            try {
                Date date = format.parse(matcher.group(1));
                obj.put("date", String.format("%tF", date));
            } catch (ParseException e) {
            }
        }
        regex = "COMPANY\\nNAME\\n(.*)\\s收";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            obj.put("payer", matcher.group(1));
        }
        regex = "应入账金额：(\\D+)((\\d{1,3},)*\\d+\\.\\d{2})";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            obj.put("currency", Bank.parseCurrency(matcher.group(1)));
            obj.put("amount", Double.parseDouble(matcher.group(2).replace(",", "")));
        }
        regex = "TYPE OF SERVICES：((\\S)+)\\s";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            String v = formatString(matcher.group(1));
            obj.put("abstract", v);
        }
        regex = "交易附言：((.*))\\n";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            String v = formatString(matcher.group(1));
            obj.put("comments", v);
        }
        regex = "内扣费用：\\D+((\\d{1,3},)*\\d+\\.\\d{2})";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            obj.put("homeCharges", Double.parseDouble(matcher.group(1).replace(",", "")));
        }
        regex = "国外扣费：\\D+((\\d{1,3},)*\\d+\\.\\d{2})";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            obj.put("foreignCharges", Double.parseDouble(matcher.group(1).replace(",", "")));
        }
        return obj;
    }

    private static JSONObject rABC(String origin) {
        JSONObject obj = new JSONObject();
        String regex = "回单编号：(\\d+)";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(origin);
        if (matcher.find()) {
            obj.put("receiptCode", matcher.group(1));
        }
        regex = "交易时间\\s(20[0-9]{2}-[0|1][0-9]-[0-3][0-9]\\s\\d{2}:\\d{2}:\\d{2})";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
            try {
                Date date = format.parse(matcher.group(1));
                obj.put("date", String.format("%tF", date));
            } catch (ParseException e) {
            }
        }
        regex = "户名\\n?\\s?((.+\\n*)+?)\\n?户名";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            String v = formatString(matcher.group(1));
            obj.put("payer", v);
        }
        regex = "金额（小写）\\s?((\\d{1,3},)*\\d+\\.\\d{2})";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            obj.put("amount", Double.parseDouble(matcher.group(1).replace(",", "")));
        }
        regex = "币种\\s(\\S+)\\s";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            obj.put("currency", Bank.parseCurrency(matcher.group(1)));
        }
        regex = "摘要\\s(.*)\\s凭证号";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            String v = formatString(matcher.group(1));
            obj.put("abstract", v);
        }
        regex = "附言\\s((.*\\n*)+?)电子回单";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(origin);
        if (matcher.find()) {
            System.out.print(matcher.groupCount());
            String v = formatString(matcher.group(1));
            obj.put("comments", v);
        }
        obj.put("homeCharges", 0.00);
        obj.put("foreignCharges", 0.00);
        return obj;
    }

    /**
     * 从PDF文件读取报关单信息
     *
     * @param sPath
     *              PDF文件路径
     *
     * @return JSONObject对象
     */
    public static JSONObject parseCDF(String sPath) {
        try {
            PDDocument document = Loader.loadPDF(new File(sPath));
            JSONObject obj = rCDF(document);
            document.close();
            return obj;
        } catch (Exception e) {
        }
        return new JSONObject();
    }

    /**
     * 从PDF文件流读取报关单信息
     *
     * @param stream
     *               PDF文件流路径
     *
     * @return JSONObject对象
     */
    public static JSONObject parseCDF(InputStream stream) {
        try {
            byte[] btys = stream.readAllBytes();
            PDDocument document = Loader.loadPDF(btys);
            JSONObject obj = rCDF(document);
            document.close();
            return obj;
        } catch (Exception e) {
        }
        return new JSONObject();
    }

    private static JSONObject rCDF(PDDocument doc) {
        JSONObject rjson = new JSONObject();
        try {
            PDFTextStripperByArea stripper = new PDFTextStripperByArea();
            Rectangle2D.Float area = new Rectangle2D.Float(364, 99, 100, 10);
            stripper.addRegion("customsCode", area);
            int y = 350;
            for (int p = 0; p < 5; p++) {
                area = new Rectangle2D.Float(44, y, 53, 50);
                stripper.addRegion("commodityCode" + p, area);
                area = new Rectangle2D.Float(105, y, 112, 50);
                stripper.addRegion("commodityName" + p, area);
                area = new Rectangle2D.Float(290, y, 68, 50);
                stripper.addRegion("commodityQuantity" + p, area);
                area = new Rectangle2D.Float(412, y, 46, 50);
                stripper.addRegion("commodityPrice" + p, area);
                area = new Rectangle2D.Float(459, y, 45, 50);
                stripper.addRegion("commodityAmount" + p, area);
                area = new Rectangle2D.Float(507, y, 30, 50);
                stripper.addRegion("commodityCurrency" + p, area);
                y += 57;
            }
            ;
            stripper.extractRegions(doc.getPage(0));
            rjson.put("customsCode",
                    stripper.getTextForRegion("customsCode").replaceAll("\\r\\n", "").replace("\n", ""));
            JSONArray arry = new JSONArray();
            for (int p = 0; p < 5; p++) {
                JSONObject t = new JSONObject();
                String[] tmp = stripper.getTextForRegion("commodityCode" + p).replaceAll("\\r\\n", "\n").split("\n");
                if (tmp.length == 0)
                    break;
                t.put("code", tmp[0].replace("\r", ""));
                tmp = stripper.getTextForRegion("commodityName" + p).split("\n");
                t.put("name", tmp[0].replace("\r", ""));
                tmp = stripper.getTextForRegion("commodityQuantity" + p).split("\n");
                JSONArray qtt = new JSONArray();
                for (int m = 0; m < tmp.length; m++) {
                    JSONObject sobj = new JSONObject();
                    String regex = "(\\d+(\\.\\d+)*)(\\D+)";
                    Pattern pattern = Pattern.compile(regex);
                    Matcher matcher = pattern.matcher(tmp[m]);
                    if (matcher.find()) {
                        sobj.put("quantity", Double.parseDouble(matcher.group(1)));
                        sobj.put("unit", matcher.group(3).replace("\r", ""));
                    }
                    qtt.add(sobj);
                }
                t.put("quantities", qtt);
                t.put("price", Double.parseDouble(
                        stripper.getTextForRegion("commodityPrice" + p).replace("\r\n", "").replace("\n", "")));
                t.put("amount", Double.parseDouble(
                        stripper.getTextForRegion("commodityAmount" + p).replace("\r\n", "").replace("\n", "")));
                t.put("currency",
                        stripper.getTextForRegion("commodityCurrency" + p).replaceFirst("\\n", "|").replace("\r\n", "")
                                .replace("\n", ""));
                arry.add(t);
            }
            ;
            rjson.put("commodities", arry);
        } catch (Exception e) {
        }
        return rjson;
    }

    private static String formatString(String origin) {
        String regex = "[\\u2E80-\\uFE4F]+\\r{0,1}\\n";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(origin);
        if (matcher.find()) {
            origin = origin.replaceAll("\\r\\n", "").replaceAll("\\n", "");
        } else {
            origin = origin.replaceAll("\\r\\n", " ").replaceAll("\\n", " ");
        }
        return origin;
    }

    /**
     * 旋转pdf
     *
     * @param oPdf
     *              需要旋转的PDF文件
     * 
     *
     * @return 旋转90度后的PDF字节流
     */
    public static ByteArrayOutputStream rotatePdf(InputStream oPdf) throws Exception {
        PDDocument doc = new PDDocument();
        PDDocument t = Loader.loadPDF(oPdf.readAllBytes());
        PDFRenderer pdfRenderer = new PDFRenderer(t);
        for (int i = 0; i < t.getNumberOfPages(); i++) {
            PDPage pg = t.getPage(i);
            int rotation=pg.getRotation();
            pg.setRotation(0);
            PDPage npg = new PDPage((pg.getMediaBox().getWidth() > pg.getMediaBox().getHeight())
                        ? new PDRectangle(PDRectangle.A4.getHeight(), PDRectangle.A4.getWidth())
                        : PDRectangle.A4);
            float srcWidth = pg.getMediaBox().getWidth();
            float srcHeight = pg.getMediaBox().getHeight();
            float destWidth = npg.getMediaBox().getWidth();
            float destHeight = npg.getMediaBox().getHeight();
            float scale = Math.min(destWidth / srcWidth, destHeight / srcHeight);
            doc.addPage(npg);
            BufferedImage image = new BufferedImage((int) destWidth*2, (int) destHeight*2, BufferedImage.TYPE_INT_RGB);
            Graphics2D graphics = image.createGraphics();
            graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
            graphics.setBackground(Color.WHITE);
            graphics.clearRect(0, 0, (int) destWidth*2, (int) destHeight*2);
            pdfRenderer.renderPageToGraphics(i, graphics, scale*2);
            PDImageXObject pdImage = LosslessFactory.createFromImage(doc, image);
            PDPageContentStream srcStream = new PDPageContentStream(doc, npg);
            srcStream.drawImage(pdImage, 0, 0,destWidth,destHeight);
            graphics.dispose();
            srcStream.close();
            npg.setRotation((rotation + 90) % 360);
        }
        t.close();
        OutputStream outstream = new ByteArrayOutputStream();
        doc.save(outstream);
        doc.close();
        return (ByteArrayOutputStream) outstream;
    }

    /**
     * 合并多个pdf文档
     *
     * @param oPdf
     *             多个PDF文件流或者文件流数组
     *
     * @return 合并后的PDF字节流
     */
    public static ByteArrayOutputStream mergePdf(InputStream... oPdf) throws Exception {
        PDDocument doc = new PDDocument();
        for (InputStream in : oPdf) {
            PDDocument t = Loader.loadPDF(in.readAllBytes());
            PDFRenderer pdfRenderer = new PDFRenderer(t);
            for (int i = 0; i < t.getNumberOfPages(); i++) {
                PDPage pg = t.getPage(i);
                int rotation=pg.getRotation();
                pg.setRotation(0);
                PDRectangle srcRect = pg.getMediaBox();
                PDPage npg = new PDPage((srcRect.getWidth() > srcRect.getHeight())
                        ? new PDRectangle(PDRectangle.A4.getHeight(), PDRectangle.A4.getWidth())
                        : PDRectangle.A4);
                float srcWidth = pg.getMediaBox().getWidth();
                float srcHeight = pg.getMediaBox().getHeight();
                float destWidth = npg.getMediaBox().getWidth();
                float destHeight = npg.getMediaBox().getHeight();
                float scale = Math.min(destWidth / srcWidth, destHeight / srcHeight);
                doc.addPage(npg);
                BufferedImage image = new BufferedImage((int) destWidth*2, (int) destHeight*2, BufferedImage.TYPE_INT_RGB);
                Graphics2D graphics = image.createGraphics();
                graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
                graphics.setBackground(Color.WHITE);
                graphics.clearRect(0, 0, (int) destWidth*2, (int) destHeight*2);
                pdfRenderer.renderPageToGraphics(i, graphics, scale*2);
                PDImageXObject pdImage = LosslessFactory.createFromImage(doc, image); 
                PDPageContentStream srcStream = new PDPageContentStream(doc, npg);
                srcStream.drawImage(pdImage, 0, 0,destWidth,destHeight);
                graphics.dispose();
                srcStream.close();
                if (srcRect.getWidth() > srcRect.getHeight())
                    npg.setRotation((rotation + 90) % 360);
            }
            t.close();
        }
        OutputStream outstream = new ByteArrayOutputStream();
        doc.save(outstream);
        doc.close();
        return (ByteArrayOutputStream) outstream;
    }

    private static void drawAlignedText(PDPageContentStream stream, String text, float x, float y,
            float maxWidth, PDFont font, float fontSize, int alignment)
            throws IOException {
        float textWidth = font.getStringWidth(text) / 1000 * fontSize;
        float startX = x;

        switch (alignment) {
            case 1:
                startX += (maxWidth - textWidth) / 2;
                break;
            case 2:
                startX += maxWidth - textWidth;
                break;
            // LEFT 无需处理
        }

        stream.beginText();
        stream.setFont(font, fontSize);
        stream.newLineAtOffset(startX, y);
        stream.showText(text);
        stream.endText();
    }

    /**
     * 生成单页pdf
     *
     * @param obj
     *            JSON对象，描述要写进pdf的内容
     *
     * @return 生成的PDF字节流
     */
    public static ByteArrayOutputStream writePdf(JSONObject obj) throws Exception {
        PDDocument doc = new PDDocument();
        PDPage pg = new PDPage(PDRectangle.A4);
        doc.addPage(pg);
        PDPageContentStream contentStream = new PDPageContentStream(doc, pg);
        JSONArray linearray = obj.getJSONArray("lines");
        for (int i = 0; i < linearray.size(); i++) {
            JSONObject p = linearray.getJSONObject(i);
            float linewidth = 1.0f;
            try {
                linewidth = p.getFloatValue("linewidth");
            } catch (Exception e) {

            }
            if (linewidth == 0.0f)
                linewidth = 1.0f;
            contentStream.setLineWidth(linewidth);
            contentStream.moveTo(p.getFloatValue("left"), p.getFloatValue("top"));
            contentStream.lineTo(p.getFloatValue("right"), p.getFloatValue("bottom"));
            contentStream.stroke();
        }
        JSONArray textsarray = obj.getJSONArray("texts");
        for (int i = 0; i < textsarray.size(); i++) {
            JSONObject p = textsarray.getJSONObject(i);
            InputStream ins = pdfparser.class.getClassLoader().getResourceAsStream("simhei.ttf");
            if (p.getString("fontfamily") != null)
                ins = pdfparser.class.getClassLoader().getResourceAsStream(p.getString("fontfamily"));
            PDFont font = PDType0Font.load(doc, ins);
            float fontsize = p.getIntValue("fontsize", 12);
            int align = p.getIntValue("align", 0);
            drawAlignedText(contentStream, p.getString("text"), p.getFloatValue("left"), p.getFloatValue("top"),
                    p.getFloatValue("width"), font, fontsize, align);
        }
        contentStream.close();
        OutputStream outstream = new ByteArrayOutputStream();
        doc.save(outstream);
        doc.close();
        return (ByteArrayOutputStream) outstream;
    }
}
